﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Printing;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using HandWriter.Controls;
using HWEngine;
using HWEngine.Configuration;
using HWEngine.Generators;
using HWEngine.Tools; 

namespace HandWriter
{
	public partial class DocumentEditorDialog : Form, IDocument
	{
		private readonly DoubleBufferGraphics _gfx = new DoubleBufferGraphics();
		private bool _disableAutoTextRendering;
		private bool _updatingControls;
		private Document _doc;

		public DocumentEditorDialog(LetterSetRepository fonts)
		{
			InitializeComponent();
			_gfx.InitDoubleBufferedGraphics(picResultsPreview);

			cmbFont.Items.AddRange(fonts.GetNames().ToArray());

			var fontSizes = new[] { "6", "8", "9", "10", "12", "14", "16", "18", "24", "32", "48", "56", "64" };
			cmbFontSize.Items.AddRange(fontSizes);

			_doc = new Document(fonts, new RtfText(edUserInput.Rtf));

			cmbFont.ComboBox.DrawItem += ComboDrawItem;
			cmbFont.ComboBox.MeasureItem += ComboMeasureItem;
			cmbFont.ComboBox.DrawMode = DrawMode.OwnerDrawFixed;
		}

		private void Document_Shown(object sender, EventArgs e)
		{
			if (edUserInput.CanFocus)
			{
				edUserInput.Focus();
			}
		}

		private void SetScrollBarRange()
		{
			vScrollBar1.Maximum = Math.Max(0, (int)(_doc.PagesCount * _doc.ListBounds.Bottom + _doc.ListBounds.Top) - picResultsPreview.Height);
			hScrollBar1.Maximum = Math.Max(0, (int)(_doc.ListBounds.Right + _doc.ListBounds.Left) - picResultsPreview.Width);
			vScrollBar1.Visible = vScrollBar1.Maximum > 0;
			hScrollBar1.Visible = hScrollBar1.Maximum > 0;
		}

		private void Generate()
		{
			var bounds = new RectangleF(hScrollBar1.Value, vScrollBar1.Value, picResultsPreview.Width, picResultsPreview.Height);
			_doc.Render(_gfx.Graphics, bounds);
			picResultsPreview.Refresh();
			SetScrollBarRange();
		}

		private void picResultsPreview_Paint(object sender, PaintEventArgs e)
		{
			_gfx.Render(e.Graphics);
		}

		private void picResultsPreview_Resize(object sender, EventArgs e)
		{
			_gfx.InitDoubleBufferedGraphics(picResultsPreview);
			SetScrollBarRange();
			Generate();
		}

		private void vScrollBar1_Scroll(object sender, ScrollEventArgs e)
		{
			Generate();
		}

		#region Rich text user input and controls

		private void UpdateTextControls()
		{
			_updatingControls = true;
			if (edUserInput.SelectionFont != null)
			{
				var selSystemFontName = edUserInput.SelectionFont.FontFamily.Name;
				cmbFont.Text = _doc.Fonts.GetBySystemFontName(selSystemFontName).FontName;
				cmbFontSize.Text = edUserInput.SelectionFont.Size.ToString();
				toolStripTextColor.SelectedColor = edUserInput.SelectionColor;
			}
			else
			{
				cmbFont.Text = String.Empty;
				cmbFontSize.Text = String.Empty;
				toolStripTextColor.SelectedColor = Color.Empty;
			}
			_updatingControls = false;
		}

		private void edUserInput_SelectionChanged(object sender, EventArgs e)
		{
			UpdateTextControls();
		}

		private void cmbFontSize_TextChanged(object sender, EventArgs e)
		{
			SetSelectionParameters(_doc.Fonts.Get(cmbFont.Text).SystemFontMatchName, cmbFontSize.Text, toolStripTextColor.SelectedColor);
		}

		private void cmbFont_TextChanged(object sender, EventArgs e)
		{
			SetSelectionParameters(_doc.Fonts.Get(cmbFont.Text).SystemFontMatchName, cmbFontSize.Text, toolStripTextColor.SelectedColor);
		}

		private void toolStripTextColor_OnColorChanged(object sender, EventArgs e)
		{
			SetSelectionParameters(_doc.Fonts.Get(cmbFont.Text).SystemFontMatchName, cmbFontSize.Text, toolStripTextColor.SelectedColor);
		}

		private void SetSelectionParameters(String fontName, String fontSize, Color color)
		{
			_disableAutoTextRendering = true;
			bool changes = false;
			if (!_updatingControls)
			{
				float fFontSize;
				if (!float.TryParse(fontSize, NumberStyles.Float, CultureInfo.InvariantCulture, out fFontSize))
				{
					fFontSize = -1;
				}
				if (edUserInput.SelectionFont != null)
				{
					if (string.IsNullOrEmpty(fontName))
					{
						fontName = edUserInput.SelectionFont.Name;
					}
					if (fFontSize < 0)
					{
						fFontSize = edUserInput.SelectionFont.Size;
					}
				}
				if (fFontSize > 0 && !string.IsNullOrEmpty(fontName))
				{
					edUserInput.SelectionFont = new Font(fontName, fFontSize);
					changes = true;
				}
				if (color != Color.Empty)
				{
					edUserInput.SelectionColor = color;
					changes = true;
				}
			}
			_disableAutoTextRendering = false;
			if (changes)
			{
				edUserInput_TextChanged(null, null);
			}
		}

		private void edUserInput_TextChanged(object sender, EventArgs e)
		{
			if (!_disableAutoTextRendering)
			{
				_doc.RtfText = new RtfText(edUserInput.Rtf);

				//auto generate
				Generate();
				picResultsPreview.Refresh();
			}
		}

		#endregion

		#region Font selector tweaks
		private void ComboMeasureItem(object sender, MeasureItemEventArgs e)
		{
			e.ItemHeight = 45;
		}

		private void ComboDrawItem(object sender, DrawItemEventArgs e)
		{
			FontItemDrawHelper.DrawItem(sender, e, ((ComboBox)sender).Items.Cast<string>().ToList(), _doc.Fonts);
		}
		#endregion

		public bool PrintingAllowed
		{
			get { return true; }
		}

		public bool ExportAllowed
		{
			get { return true; }
		}

		public bool SaveAllowed
		{
			get { return true; }
		}

		public bool SaveAsAllowed
		{
			get { return true; }
		}

		public bool SaveAllAllowed
		{
			get { return false; }
		}

		public Form Form
		{
			get { return this; }
		}

		public void Print()
		{
			using (var pdialog = new PrintDialog())
			{
				if (pdialog.ShowDialog() == DialogResult.OK)
				{
					var pd = new PrintDocument();
					pd.PrinterSettings = pdialog.PrinterSettings;
					pd.PrintPage += _doc.PrintHandler;
					_doc.BeginPrinting();
					pd.Print();
				}
			}
		}

		public void Save()
		{
			MessageBox.Show("not implemented");
		}

		public void SaveAs()
		{
			MessageBox.Show("not implemented");
		}

		public void SaveAll()
		{
			throw new NotImplementedException();
		}

		public void Export()
		{
			using (var d = new SaveFileDialog())
			{
				d.Filter = "svg file|*.svg";
				if (d.ShowDialog() == DialogResult.OK)
				{
					_doc.ExportToSvg(d.FileName);
				}
			}
		}
	}
}
